package com.common.util;

import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redis是键值对数据库
 * 我们使用java提供的模板工具类，我们就可以直接操作redis,存取token
 */
@NoArgsConstructor
@Component
public class RedisUtil {

    // 从application.yml引入token过期秒数
    @Value("${token.expirationSeconds}")
    private int expirationSeconds;
    // 从application.yml引入有效时间
    @Value("${token.validTime}")
    private int validTime;

    //创建redis模板
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 获取所有的键
     *
     * @param key
     * @return Set<String>
     */
    public Set<String> keys(String key) {
        return this.redisTemplate.keys(key);
    }

    /**
     * 通过键名，获取键值对象
     *
     * @param key
     * @return
     */
    public Object get(String key) {
        return this.redisTemplate.opsForValue().get(key);
    }

    /**
     * 存键值对象
     *
     * @param key
     * @param value
     */
    public void set(String key, String value) {
        this.redisTemplate.opsForValue().set(key, value, 7200L, TimeUnit.SECONDS);
    }

    /**
     * 存键值对象
     *
     * @param key
     * @param value
     * @param expire 时间(秒) expire要大于0 如果expire小于等于0 将设置无限期
     */
    public void set(String key, String value, Integer expire) {
        this.redisTemplate.opsForValue().set(key, value, (long) expire, TimeUnit.SECONDS);
    }

    /**
     * HashSet
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key    键
     * @param filed  值
     * @param domain
     */
    public void setHash(String key, String filed, Object domain) {
        this.redisTemplate.opsForHash().put(key, filed, domain);
    }

    /**
     * @param key     key
     * @param hashKey map的key
     * @param domain  map的value
     * @param expire  如果已存在的hash表有时间,这里将会替换原有的时间
     */
    public void putHash(String key, String hashKey, Object domain, Integer expire) {
        this.redisTemplate.opsForHash().put(key, hashKey, domain);
        this.redisTemplate.expire(key, (long) expire, TimeUnit.SECONDS);
    }

    /**
     * @param key    key
     * @param map    数据Map
     * @param expire 过期时间（毫秒）
     */
    public void putHash(String key, Map<String, Object> map, Integer expire) {
        this.redisTemplate.opsForHash().putAll(key, map);
        this.redisTemplate.expire(key, (long) expire, TimeUnit.SECONDS);
    }

    /**
     * hashSet
     *
     * @param key 键
     * @param hm  多个键值
     */
    public void hset(String key, HashMap<String, Object> hm) {
        this.redisTemplate.opsForHash().putAll(key, hm);
    }


    public void hsetAbsent(String key, String filed, Object domain) {
        this.redisTemplate.opsForHash().putIfAbsent(key, filed, domain);
    }

    /**
     * @param key
     * @param field
     */
    public Object getHash(String key, String field) {
        return this.redisTemplate.opsForHash().get(key, field);
    }

    public Object getHash(String key) {
        return this.redisTemplate.opsForHash().entries(key);
    }

    /**
     * 删除缓存键值对
     *
     * @param key key
     */
    public void deleteKey(String key) {
        this.redisTemplate.delete(key);
    }

    public Boolean hasKey(String key, String field) {
        return this.redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * 判断key是否存在
     *
     * @param key
     * @return boolean
     */
    public Boolean hasKey(String key) {
        return this.redisTemplate.opsForHash().getOperations().hasKey(key);
    }

    /**
     * 判断 token 是否在黑名单内
     */
    public Boolean isBlackList(String token) {
        return this.hasKey("blacklist", token);
    }

    /**
     * 将 token 添加人黑名单
     */
    public void addBlackList(String token) {
        this.setHash("blacklist", token, "true");
    }

    /**
     * 设置 token 的过期时间、有效时间、实体、ip
     *
     * @param token    token
     * @param username 用户登陆账号
     * @param ip       用户访问IP
     */
    public void setTokenRefresh(String token, String userId, String username, String ip, String auths) {
        Map<String, Object> redisMap = new HashMap<>();
        redisMap.put("userId", userId);
        redisMap.put("username", username);
        redisMap.put("ip", ip);
        redisMap.put("tokenValidTime", DateUtil.getAddDayTime(validTime));//token有效期
        redisMap.put("expirationTime", DateUtil.getAddDaySecond(expirationSeconds));//token存活时间
        redisMap.put("auths", auths);
        putHash(token, redisMap, validTime * 24 * 60 * 60);
    }
}
